package server

import (
	"context"
	"crypto/rand"
	"encoding/hex"
	"log/slog"
	"server/internal/core/constant"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

var (
	// traceIDPool 使用 sync.Pool 管理 trace ID 字节数组
	// sync.Pool 会自动管理对象生命周期，GC 时自动清理未使用的对象
	traceIDPool = &sync.Pool{
		New: func() any {
			return new([16]byte)
		},
	}
)

// Logger 记录请求和响应日志的中间件
func Logger(log *slog.Logger) gin.HandlerFunc {
	return func(c *gin.Context) {
		// 生成并设置 trace ID，如果header中存在trace_id，则使用header中的trace_id
		traceID := c.GetHeader(constant.TraceIDKey)
		if traceID == "" {
			traceID = generateTraceID()
		}

		// 设置 trace ID 到 Request.Context
		ctx := context.WithValue(c.Request.Context(), constant.TraceIDKeyType{}, traceID)
		c.Request = c.Request.WithContext(ctx)    // 设置 trace ID 到 Request.Context
		c.Set(constant.TraceIDKeyType{}, traceID) // 设置 trace ID 到 Context

		// 记录开始时
		start := time.Now()

		// 处理请求
		c.Next()

		// 计算耗时
		latency := time.Since(start)

		// 记录请求和响应日志
		reqBody, _ := c.GetRawData()
		reqBodyStr := string(reqBody)
		if len(reqBodyStr) > 1024 {
			reqBodyStr = reqBodyStr[:1024] + "..."
		}

		log.LogAttrs(c.Request.Context(), slog.LevelInfo, "response info",
			slog.Group("request",
				slog.String("method", c.Request.Method),
				slog.String("path", c.Request.URL.Path),
				slog.String("query", c.Request.URL.RawQuery),
				slog.String("body", string(reqBodyStr)),
			),
			slog.Group("response",
				slog.String("method", c.Request.Method),
				slog.Int("status", c.Writer.Status()),
				slog.Duration("latency", latency),
				slog.Int("size", c.Writer.Size()),
			),
		)
	}
}

// generateTraceID 生成追踪ID（使用 sync.Pool 优化性能）
func generateTraceID() string {
	// 从池中获取字节数组指针
	b := traceIDPool.Get().(*[16]byte)
	defer traceIDPool.Put(b) // 确保归还到池中

	// 生成随机字节
	_, err := rand.Read(b[:])
	if err != nil {
		return ""
	}
	// 转换为十六进制字符串
	return hex.EncodeToString(b[:])
}
